HackPack Exhell Write Up
Details:
Jeopardy style CTF
Category: Reverse Engineering
Comments:
I'm tired of the IT department laughing at me when they see how much I spend on cans of effervescent water. That's why I've decided to secure my expences with password, so that nobody will laugh at me ever again! 😤
Write up:
I used binwalk to extract all the information from the .xlsx file. I was then able to get the xml for the two sheets. The important information was in sheet2.xml.
At first I tried to use Z3 and making a python script to write the Z3 script, my teammate pointed out that was unecessary so he made a quick script to parse the xml, then we used sympy to solve for all of the B cell values. I then added a portion for converting the B values to ascii values:
# imports
import xml.etree.ElementTree as ET
import sympy
import json
import re
# import sheet
tree = ET.parse('sheet2.xml')
root = tree.getroot()
data = root[4]
values = {"K1": True}
op = {"OR": " | ", "AND": " & ", "NOT": "~", "FALSE": False, "TRUE": True}
# process all the data
def process_formula(formula):
if formula == "FALSE()" or formula == "TRUE()":
return op[formula[:-2]]
pos_open_bracket = formula.index('(')
new_formula = formula[pos_open_bracket:].replace('NOT', op["NOT"])
new_formula = new_formula.replace(",", op[formula[:pos_open_bracket]])
return new_formula
def get_answer(formula, expected=False):
if not expected:
formula = '~{}'.format(formula)
if re.match(r".*E1[^0-9].*", formula):
formula = formula.replace("E1", "x")
p = sympy.satisfiable(sympy.parse_expr(formula, evaluate=False))
u = list(p.keys())
new_p = {i.name: p[i] for i in u}
if "x" in new_p:
new_p["E1"] = new_p["x"]
del new_p["x"]
return new_p
def process_col(col):
global values
if 'A' not in col.attrib['r'] and 'B' not in col.attrib['r']:
_op = process_formula(col[0].text)
if _op in (True, False):
values[col.attrib['r']] = _op
else:
values.update(get_answer(_op, values[col.attrib['r']]))
def process_row(row):
for col in row[::-1]:
process_col(col)
for row in data:
process_row(row)
values_b = list(filter(lambda x: 'B' in x, values.keys()))
values_b = {i:values[i] for i in values_b}
# create array for B values
Bvals = [0 for i in range(0, len(values_b))]
# turn to binary and then ascii
for i in values_b:
Bvals[int(i.replace('B', ''))-1] = 1 if values_b[i] else 0
s = ""
for i in range(0, len(Bvals), 8):
curVal = ""
for j in range(0, 8):
curVal += str(Bvals[i+j])
s += chr(int(curVal, 2))
print(s)
Once run this output:
flag{0h_g33z_th4t5_a_l0t_sp3nt_0n_L3Cr0ix}